import 'package:flutter/material.dart';

///向下传递约束,向上传递大小,上层决定下层位置
///细节
///Widget 会通过它的 父级 获得自身的约束。 约束实际上就是 4 个浮点类型的集合： 最大/最小宽度，以及最大/最小高度。
///然后，这个 widget 将会逐个遍历它的 children 列表。向子级传递 约束（子级之间的约束可能会有所不同），然后询问它的每一个子级需要用于布局的大小。
///然后，这个 widget 就会对它子级的 children 逐个进行布局。 （水平方向是 x 轴，竖直是 y 轴）
///最后，widget 将会把它的大小信息向上传递至父 widget（包括其原始约束条件）。
///https://blog.csdn.net/weixin_43459071/article/details/107176987

test() {
  //根 -》
  Container(color: Colors.red);
  //充满了整个屏幕，并绘制成红色

  //根 -》
  Container(width: 100, height: 100, color: Colors.red);
  //红色的 Container 想要变成 100 x 100 的大小， 但是它无法变成，因为屏幕强制它变成和屏幕一样的大小。

  //根 -》
  Center(child: Container(width: 100, height: 100, color: Colors.red));
  //Center 充满了屏幕。
  //Center 告诉 Container 可以变成任意大小，但是不能超出屏幕。
  //Container 可以真正变成 100 × 100 大小了。

  //根 -》
  Align(
    alignment: Alignment.bottomRight,
    child: Container(width: 100, height: 100, color: Colors.red),
  );
  //Align 充满了屏幕。
  //Align 同样也告诉 Container，你可以变成任意大小。
  //但是，如果还留有空白空间的话，它不会居中 Container。
  //相反，它将会在允许的空间内，把 Container 放在右下角（bottomRight）。

  //根 -》
  Center(
      child: Container(
        color: Colors.red,
        width: double.infinity,
        height: double.infinity,
      ));
  //屏幕强制 Center 变得和屏幕一样大，所以 Center 充满屏幕。
  //然后 Center 告诉 Container 可以变成任意大小，但是不能超出屏幕。
  //现在，Container 想要无限的大小，但是由于它不能比屏幕更大， 所以就仅充满屏幕。

  //根 -》
  Center(child: Container(color: Colors.red));
  //屏幕强制 Center 变得和屏幕一样大，所以 Center 充满屏幕。
  //然后 Center 告诉 Container 可以变成任意大小，但是不能超出屏幕。
  //由于 Container 没有子级而且没有固定大小，所以它决定能有多大就有多大， 所以它充满了整个屏幕。
  //但是，为什么 Container 做出了这个决定？ 非常简单，因为这个决定是由 Container widget 的创建者决定的。
  //可能会因创造者而异，而且你还得阅读 Container 文档 来理解不同场景下它的行为。

  //根 -》
  Center(
      child: Container(
        color: Colors.red,
        child: Container(color: Colors.green, width: 30, height: 30),
      ));
  //屏幕强制 Center 变得和屏幕一样大，所以 Center 充满屏幕。
  //然后 Center 告诉红色的 Container 可以变成任意大小，但是不能超出屏幕。
  //由于 Container 没有固定大小但是有子级，所以它决定变成它 child 的大小。
  //然后红色的 Container 告诉它的 child 可以变成任意大小，但是不能超出屏幕。
  //而它的 child 是一个想要 30 × 30 大小绿色的 Container。由于红色的 Container 和其子级一样大，
  //所以也变为 30 × 30。由于绿色的 Container 完全覆盖了红色 Container， 所以你看不见它了。

  //根 -》
  Center(
      child: Container(
        color: Colors.red,
        padding: const EdgeInsets.all(20.0),
        child: Container(color: Colors.green, width: 30, height: 30),
      ));
  //红色 Container 变为其子级的大小，但是它将其 padding 带入了约束的计算中。
  //所以它有一个 30 x 30 的外边距。由于这个外边距，所以现在你能看见红色了。
  //而绿色的 Container 则还是和之前一样。

  //根 -》
  ConstrainedBox(
    constraints: BoxConstraints(
      minWidth: 70,
      minHeight: 70,
      maxWidth: 150,
      maxHeight: 150,
    ),
    child: Container(color: Colors.red, width: 10, height: 10),
  );
  //ConstrainedBox 仅对其从其父级接收到的约束下施加其他约束。
  //在这里，屏幕迫使 ConstrainedBox 与屏幕大小完全相同， 因此它告诉其子 Widget 也以屏幕大小作为约束，
  //从而忽略了其 constraints 参数带来的影响。

  //根 -》
  Center(
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minWidth: 70,
          minHeight: 70,
          maxWidth: 150,
          maxHeight: 150,
        ),
        child: Container(color: Colors.red, width: 10, height: 10),
      ));
  //Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。
  // ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
  //Container 必须介于 70 到 150 像素之间。虽然它希望自己有 10 个像素大小， 但最终获得了 70 个像素（最小为 70）。

  //根 -》
  Center(
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minWidth: 70,
          minHeight: 70,
          maxWidth: 150,
          maxHeight: 150,
        ),
        child: Container(color: Colors.red, width: 1000, height: 1000),
      ));
  //Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。
  //ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
  //Container 必须介于 70 到 150 像素之间。 虽然它希望自己有 1000 个像素大小，
  //但最终获得了 150 个像素（最大为 150）。

  //根 -》
  Center(
      child: ConstrainedBox(
        constraints: BoxConstraints(
          minWidth: 70,
          minHeight: 70,
          maxWidth: 150,
          maxHeight: 150,
        ),
        child: Container(color: Colors.red, width: 100, height: 100),
      ));
  //Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。
  //ConstrainedBox 将 constraints 参数带来的约束附加到其子对象上。
  //Container 必须介于 70 到 150 像素之间。 虽然它希望自己有 100 个像素大小，
  //因为 100 介于 70 至 150 的范围内，所以最终获得了 100 个像素。

  //根 -》
  UnconstrainedBox(
    child: Container(color: Colors.red, width: 20, height: 50),
  );
  //屏幕强制 UnconstrainedBox 变得和屏幕一样大，而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。

  //根 -》
  UnconstrainedBox(
    child: Container(color: Colors.red, width: 4000, height: 50),
  );
  //屏幕强制 UnconstrainedBox 变得和屏幕一样大， 而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。
  //不幸的是，在这种情况下，容器的宽度为 4000 像素， 这实在是太大，以至于无法容纳在 UnconstrainedBox 中，
  //因此 UnconstrainedBox 将显示溢出警告（overflow warning）。

  //根 -》
  OverflowBox(
    minWidth: 0.0,
    minHeight: 0.0,
    maxWidth: double.infinity,
    maxHeight: double.infinity,
    child: Container(color: Colors.red, width: 4000, height: 50),
  );
  //屏幕强制 OverflowBox 变得和屏幕一样大， 并且 OverflowBox 允许其子容器设置为任意大小。
  //OverflowBox 与 UnconstrainedBox 类似，但不同的是， 如果其子级超出该空间，它将不会显示任何警告。
  //在这种情况下，容器的宽度为 4000 像素，并且太大而无法容纳在 OverflowBox 中，
  //但是 OverflowBox 会全部显示，而不会发出警告。

  //根 -》
  UnconstrainedBox(
      child: Container(
        color: Colors.red,
        width: double.infinity,
        height: 100,
      ));
  //这将不会渲染任何东西，而且你能在控制台看到错误信息。
  //UnconstrainedBox 让它的子级决定成为任何大小， 但是其子级是一个具有无限大小的 Container。
  //Flutter 无法渲染无限大的东西，所以它抛出以下错误： BoxConstraints forces an infinite width.
  //（盒子约束强制使用了无限的宽度）

  //根 -》
  UnconstrainedBox(
      child: LimitedBox(
          maxWidth: 100,
          child: Container(
            color: Colors.red,
            width: double.infinity,
            height: 100,
          )));
  //UnconstrainedBox 给 LimitedBox 一个无限的大小； 但它向其子级传递了最大为 100 的约束。
  //如果你将 UnconstrainedBox 替换为 Center， 则LimitedBox 将不再应用其限制（因为其限制仅在获得无限约束时才适用），
  //并且容器的宽度允许超过 100。

  //根 -》
  FittedBox(
    child: Text('Some Example Text.'),
  );
  //屏幕强制 FittedBox 变得和屏幕一样大， 而 Text 则是有一个自然宽度（也被称作 intrinsic 宽度），
  //它取决于文本数量，字体大小等因素。
  //FittedBox 让 Text 可以变为任意大小。 但是在 Text 告诉 FittedBox 其大小后，
  //FittedBox 缩放文本直到填满所有可用宽度。

  //根 -》
  Center(
      child: FittedBox(
        child: Text('Some Example Text.'),
      ));
  //Center 将会让 FittedBox 能够变为任意大小， 取决于屏幕大小。
  //FittedBox 然后会根据 Text 调整自己的大小， 然后让 Text 可以变为所需的任意大小，
  //由于二者具有同一大小，因此不会发生缩放。

  //根 -》
  Center(
      child: FittedBox(
        child: Text(
            'This is some very very very large text that is too big to fit a regular screen in a single line.'),
      ));
  //如果 FittedBox 位于 Center 中， 但 Text 太大而超出屏幕，会发生什么？
  //FittedBox 会尝试根据 Text 大小调整大小， 但不能大于屏幕大小。然后假定屏幕大小，
  //并调整 Text 的大小以使其也适合屏幕。

  //根 -》
  Center(
    child: Text(
        'This is some very very very large text that is too big to fit a regular screen in a single line.'),
  );
  //如果你删除了 FittedBox， Text 则会从屏幕上获取其最大宽度， 并在合适的地方换行。

  //根 -》
  FittedBox(
      child: Container(
        height: 20.0,
        width: double.infinity,
      ));
  //FittedBox 只能在有限制的宽高中 对子 widget 进行缩放（宽度和高度不会变得无限大）。
  //否则，它将无法渲染任何内容，并且你会在控制台中看到错误。

  //根 -》
  Row(children: [
    Container(color: Colors.red, child: Text('Hello!')),
    Container(color: Colors.green, child: Text('Goodbye!')),
  ]);
  //屏幕强制 Row 变得和屏幕一样大，所以 Row 充满屏幕。
  //和 UnconstrainedBox 一样， Row 也不会对其子代施加任何约束， 而是让它们成为所需的任意大小。
  //Row 然后将它们并排放置， 任何多余的空间都将保持空白。

  //根 -》
  Row(children: [
    Container(
        color: Colors.red,
        child: Text('This is a very long text that won’t fit the line.')),
    Container(color: Colors.green, child: Text('Goodbye!')),
  ]);
  //由于 Row 不会对其子级施加任何约束， 因此它的 children 很有可能太大 而超出 Row 的可用宽度。
  //在这种情况下， Row 会和 UnconstrainedBox 一样显示溢出警告。

  //根 -》
  Row(children: [
    Expanded(
        child: Container(
            color: Colors.red,
            child: Text('This is a very long text that won’t fit the line.'))),
    Container(color: Colors.green, child: Text('Goodbye!')),
  ]);
  //当 Row 的子级被包裹在了 Expanded widget 之后， Row 将不会再让其决定自身的宽度了。
  //取而代之的是，Row 会根据所有 Expanded 的子级 来计算其该有的宽度。
  //换句话说，一旦你使用 Expanded， 子级自身的宽度就变得无关紧要，直接会被忽略掉。

  //根 -》
  Row(children: [
    Expanded(
        child: Container(
            color: Colors.red,
            child: Text('This is a very long text that won’t fit the line.'))),
    Expanded(child: Container(color: Colors.green, child: Text('Goodbye!'))),
  ]);
  //如果所有 Row 的子级都被包裹了 Expanded widget， 每一个 Expanded 大小都会与其 flex 因子成比例，
  //并且 Expanded widget 将会强制其子级具有与 Expanded 相同的宽度。
  //换句话说，Expanded 忽略了其子 Widget 想要的宽度。

  //根 -》
  Row(children: [
    Flexible(
        child: Container(color: Colors.red,
            child: Text('This is a very long text that won’t fit the line.'))),
    Flexible(
        child: Container(color: Colors.green, child: Text('Goodbye!'))),
  ]);
  //如果你使用 Flexible 而不是 Expanded 的话， 唯一的区别是，Flexible 会让其子级具有与 Flexible 相同或者更小的宽度。 而 Expanded 将会强制其子级具有和 Expanded 相同的宽度。 但无论是 Expanded 还是 Flexible 在它们决定子级大小时都会忽略其宽度。
  //这意味着，Row 要么使用子级的宽度， 要么使用Expanded 和 Flexible 从而忽略子级的宽度。

  //根 -》
  Scaffold(
      body: Container(
          color: Colors.blue,
          child: Column(
              children: [
                Text('Hello!'),
                Text('Goodbye!'),
              ]
          )));
  //屏幕强制 Scaffold 变得和屏幕一样大， 所以 Scaffold 充满屏幕。
  //然后 Scaffold 告诉 Container 可以变为任意大小， 但不能超出屏幕。
  //当一个 widget 告诉其子级可以比自身更小的话， 我们通常称这个 widget 对其子级使用 宽松约束（loose）。

  //根 -》
  Scaffold(
      body: SizedBox.expand(
          child: Container(
              color: Colors.blue,
              child: Column(
                children: [
                  Text('Hello!'),
                  Text('Goodbye!'),
                ],
              ))));
  //如果你想要 Scaffold 的子级变得和 Scaffold 本身一样大的话， 你可以将这个子级外包裹一个 SizedBox.expand。
  //当一个 widget 告诉它的子级必须变成某个大小的时候， 我们通常称这个 widget 对其子级使用 严格约束（tight）。
}

test2() {
  //严格约束（Tight） vs 宽松约束（loose）
  //以后你经常会听到一些约束为严格约束或宽松约束， 你花点时间来弄明白它们是值得的。
  //严格约束给你了一种获得确切大小的选择。 换句话来说就是，它的最大/最小宽度是一致的，高度也一样。
}

main() {
  test();
}
